/*
 *  Copyright (C) 2011 glauco
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.swing.builders;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import org.balisunrise.annotation.EventType;
import org.balisunrise.annotation.FilterType;
import org.balisunrise.annotation.util.CriteriaUtilities;
import org.balisunrise.annotation.util.FieldUtilities;
import org.balisunrise.annotation.util.NameUtil;
import org.balisunrise.application.Application;
import org.balisunrise.application.ComponentManagers;
import org.balisunrise.builder.BuilderException;
import org.balisunrise.common.Action;
import org.balisunrise.common.ActionProvider;
import org.balisunrise.common.ComponentManager;
import org.balisunrise.common.FieldComponent;
import org.balisunrise.common.IconManager;
import org.balisunrise.common.PropertiesReader;
import org.balisunrise.swing.commons.FieldInput;
import org.balisunrise.swing.commons.FieldLabel;
import org.balisunrise.swing.commons.SelectionAction;
import org.balisunrise.swing.commons.listeners.FieldInputListener;
import org.balisunrise.swing.components.ComponentFactory;

/**
 * Classe que constrói componetes para campos.
 *
 * @author glauco
 * @see org.balisunrise.common.FieldComponent
 */
public class FieldComponentsBuilder {

    private static final int LABEL = 0;
    private static final int INFO_LABEL = 1;
    private static final int UNTIL = 2;

    public static List<FieldComponent>
            buildPanelFieldComponets(FieldUtilities fu)
            throws BuilderException{

        List<FieldComponent> list = new
                ArrayList<FieldComponent>();

        // adicina o label
        list.add(buildFieldLabel(fu));
        // adicina o input
        list.add(buildFieldInput(fu.alias, fu.field.getDeclaringClass(),
                fu.field.getType(), fu.field.getName(), fu.aligment,
                fu.bindReadOnly, fu.properties, null));
        // adiciona a info
        if (fu.infoLabel != null && fu.infoLabel.length() > 0)
            list.add(buildFieldInfoLabel(fu));

        return list;
    }

    public static List<FieldComponent>
            buildFilterFieldComponents(CriteriaUtilities cu)
            throws BuilderException{

        List<FieldComponent> list = new
                ArrayList<FieldComponent>();

        // adicina o label
        list.add(buildFieldLabel(cu));
        // adicina o input
        list.add(buildFieldInput(cu.alias, cu.field.getDeclaringClass(),
                cu.field.getType(), cu.field.getName(), cu.aligment,
                false, cu.properties, "-1"));
        // se for filtro entre
        if(cu.filterType == FilterType.BETWEEN){
            // adicional lable até
            list.add(buildFieldUntilLabel(cu));
            // adiciona segundo input
            list.add(buildFieldInput(cu.alias, cu.field.getDeclaringClass(),
                cu.field.getType(), cu.field.getName(), cu.aligment,
                false, cu.properties, "-2"));
        }

        return list;
    }

    public static FieldLabel buildFieldLabel(FieldUtilities fu)
            throws BuilderException {

        return buildFieldLabel(fu.alias,fu.field.getDeclaringClass(),
                fu.field.getClass(), fu.field.getName(), fu.label, LABEL);
    }

    public static FieldLabel buildFieldLabel(CriteriaUtilities cu)
            throws BuilderException {

        return buildFieldLabel(cu.alias,cu.field.getDeclaringClass(),
                cu.field.getClass(), cu.field.getName(), cu.label, LABEL);
    }

    public static FieldLabel buildFieldUntilLabel(CriteriaUtilities cu)
            throws BuilderException {

        String text = Application.get().getPropertiesReader()
                    .readProperty(PropertiesReader.messageTO);

        return buildFieldLabel(cu.alias,cu.field.getDeclaringClass(),
                cu.field.getClass(), cu.field.getName(), text, UNTIL);
    }

    public static FieldInput buildFieldInput(String alias, Class entityClass,
            Class fieldClass, String fieldName, int aligment,
            boolean bindReadOnly, Properties properties, String nameSufix)
            throws BuilderException{

        // pega CM
        ComponentManagers cms = Application.get().getComponentManagers();
        ComponentManager<?,JComponent> cm =
                cms.getComponentManager(fieldClass);
        // cria componente
        JComponent component = cm.buildComponent(properties);
        // cria FI
        FieldInput fi = new FieldInput(component, !bindReadOnly);

        // atribuições
        fi.setAlias(alias);
        fi.setEntityClass(entityClass);
        fi.setFieldClass(fieldClass);
        fi.setFieldName(fieldName);
        fi.setAlignment(aligment);

        // Action Provider
        ActionProvider ap = Application.get().getActionMapManager()
                .getActionProvider(entityClass);

        // listener de eventos do um campo input
        FieldInputListener fil = new FieldInputListener();
        fi.addFieldInputListener(fil);

        // ações de eventos de gotFocus
        Action[] as = ap.getActions(EventType.FIELD_GOT_FOCUS, alias, fieldName);
        for (Action action : as) {
            action.setOwner(fi);
            fil.addGotFocusAction(action);
        }

        // ações de saida de focus
        as = ap.getActions(EventType.FIELD_LOST_FOCUS, alias, fieldName);
        for (Action action : as) {
            action.setOwner(fi);
            fil.addLostFocusAction(action);
        }

        // ações de focus traversal
        as = ap.getActions(EventType.FIELD_FOCUS_TRAVEL, alias, fieldName);
        for (Action action : as) {
            action.setOwner(fi);
            fil.addFocusTraversalAction(action);
        }

        // ações depois de sincronizar
        as = ap.getActions(EventType.FIELD_SYNC, alias, fieldName);
        for (Action action : as) {
            action.setOwner(fi);
            fil.addAfterSyncAction(action);
        }

        // nome do FI
        String name = NameUtil.buildName(fi) + ":component" +
                (nameSufix == null ? "" : nameSufix);
        fi.setName(name);
        component.setName(name);
        component.getAccessibleContext().setAccessibleName(name);

        return fi;
    }

    public static FieldLabel buildFieldInfoLabel(FieldUtilities fu)
            throws BuilderException{

        return buildFieldLabel(fu.alias,fu.field.getDeclaringClass(),
                fu.field.getClass(), fu.field.getName(), fu.infoLabel,
                INFO_LABEL);
    }

    public static SelectionAction buildSelectionAction(FieldUtilities fu)
            throws BuilderException{

        SelectionAction sa = new SelectionAction();
        sa.setAlias(fu.alias);
        sa.setEntityClass(fu.field.getDeclaringClass());
        sa.setFieldClass(fu.field.getType());
        sa.setFieldName(fu.field.getName());
        sa.setAlignment(fu.aligment);

        IconManager<ImageIcon> im = Application.get().getIconManager();
        PropertiesReader pr = Application.get().getPropertiesReader();
        JLabel image = ComponentFactory.fieldActionIcon(im.PROMPT, sa);
        image.setToolTipText(pr.readProperty(pr.searchToolTipText));
        
        sa.setVisualRepresentation(image);
        sa.setNotFoundMessage(fu.notFoundMessage);
        sa.setSearchAlias(fu.search);

        String name = NameUtil.buildName(sa);
        image.setName(name);
        image.getAccessibleContext().setAccessibleName(name);
        sa.setName(name);

        return sa;
    }

    private static FieldLabel buildFieldLabel(String alias, Class entityClass,
            Class fieldClass, String fieldName, String text, int type)
            throws BuilderException {

        // cria representação visual
        JLabel label = new JLabel(text);
        // cria fieldLabel
        FieldLabel fl = new FieldLabel(label);

        fl.setAlias(alias);
        fl.setEntityClass(entityClass);
        fl.setFieldClass(fieldClass);
        fl.setFieldName(fieldName);
        fl.setAlignment(0);

        String name = NameUtil.buildName(fl) ;
        switch (type) {
            case LABEL:
                name += ":label";
                break;
            case INFO_LABEL:
                name += ":infoLabel";
                break;
            case UNTIL:
                name += ":untilLabel";
                break;
        }
        fl.setName(name);
        label.setName(name);
        label.getAccessibleContext().setAccessibleName(name);

        return fl;
    }
}
